package com.thghh.bcode.decompiler;
import java.io.*;

import com.strobel.assembler.metadata.*;
import com.strobel.decompiler.DecompilationOptions;
import com.strobel.decompiler.DecompilerSettings;
import com.strobel.decompiler.languages.java.JavaFormattingOptions;

/**
 * @author Zhikang.Peng
 * @version 1.0
 * @email thghh@qq.com
 * @date 2020/12/4 15:53
 */
public class DynamicClassDecompiler {

    private DecompilerSettings decompilerSettings;
    private DecompilationOptions decompilationOptions;

    public DynamicClassDecompiler() {
        decompilerSettings = new DecompilerSettings();
        if (decompilerSettings.getJavaFormattingOptions() == null) {
            decompilerSettings.setJavaFormattingOptions(JavaFormattingOptions.createDefault());
        }
        decompilationOptions = new DecompilationOptions();
        decompilationOptions.setSettings(decompilerSettings);
        decompilationOptions.setFullDecompilation(true);
    }

    public String decompiler(File f) throws IOException {
        try(InputStream input = new BufferedInputStream(new FileInputStream(f))) {
            return decompiler(input);
        }
    }

    public String decompiler(InputStream input) throws IOException {
        byte[] byteCode = new byte[1024];
        int count;
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        while((count = input.read(byteCode)) != -1) {
            output.write(byteCode, 0, count);
        }
        return decompiler(output.toByteArray());
    }

    public String decompiler(byte[] byteCode) {
        ArrayTypeLoader byteCodeLoader = new ArrayTypeLoader(byteCode);
        MetadataSystem metadataSystem = new MetadataSystem(byteCodeLoader);
        TypeReference typeReference = metadataSystem.lookupType(byteCodeLoader.getClassNameFromArray());
        TypeDefinition  typeDefinition = typeReference.resolve();

        DecompilerLinkProvider newLinkProvider = new DecompilerLinkProvider();
        newLinkProvider.setDecompilerReferences(metadataSystem, decompilerSettings, decompilationOptions);
        newLinkProvider.setType(typeDefinition);
        newLinkProvider.generateContent();
        return newLinkProvider.getTextContent();
    }
}
